/**
 *
 * $Id: PositionClient.i,v 1.5 2009-10-12 22:16:42 ttaipalu Exp $
 *
 * \file PositionClient.i
 * \brief MaCI - Python wrapper for Position Interface Client
 * \author Antti Maula <antti.maula@tkk.fi>
 * \author Tapio Taipalus <tapio.taipalus@tkk.fi>
 */

%module PositionClient

%include std_string.i
%include std_list.i
%include std_map.i
%include "typemaps.i"
%include "../MaCIError.i"
%include "../MaCICtrl/MaCICtrlClient.i"
%include "../common/timestamp.i"

%{
#include "MaCI.hpp"
#include "PositionData.hpp"
#include "thread.hpp"
#include "sync.hpp"
#include "databacklog.hpp"
#include <map>
#include "PositionClient.hpp"
%}

%include "PositionData.i"
%include "PositionTypes.i"
%include "../MaCIError.i"
%include "../MaCICtrl/MaCICtrlClient.i"


// Forward declare gimi::GIMI
namespace gimi {
  class GIMI;
}

namespace MaCI {
  namespace Position {

    // Forward declare for CPositionClientCallback
    class CPositionClient;

    /** Callback interface class for Position interface.
     *
     * This interface defines functions which can be used for
     * PositionClient callbacks. These functions are executed (more
     * detail per function basis) as new data arrives, and directly
     * from the context of the receiving thread. <b>Therefore, it is
     * important that the handling function is as simple and fast as
     * possible, as it will block the execution of the receiving
     * thread while executed.</b>
     */
    class CPositionClientCallback
    {
    public:

      CPositionClientCallback() {}
      virtual ~CPositionClientCallback() {}


      /** Handler function for PositionData event.
       *
       * This function is called when the PositionClient receives new
       * data from the server.
       *
       * \note <b>Keep this function simple & fast as it will block the 
       * data receiving thread while executing!</b>
       *
       * @param[in] aData       Constant reference to CPositionData element 
       *                        containing the received event.
       * @param[in] aDataSequence Sequence number of the received data. 
       *                        This should increment by one on each call.
       * @param[in] aPositionClient Reference to PositionClient 
       *                        instance which received this event.
       */
      virtual void OnPositionDataEvent(const MaCI::Position::CPositionData &aData, 
                                       const unsigned int aDataSequence,
                                       MaCI::Position::CPositionClient &aPositionClient) = 0;
    };

    /** Type for storing multiple positions
     *
     */
    typedef std::list<CPositionData> TPositionDataArray;


    /** Position event types.
     */
    enum EPositionEvent {
      KEventPositionData = 0 ///< PositionData element received and stored.
    };


    /** MaCI - Position Client interface.
     * 
     * This class contains the methods and types for using
     * a MaCI::Position service in the GIMnet.
     */
    class CPositionClient : private gim::CSync,
                            private gim::CThread,
                            public MaCI::CMaCI
    {
    public:
      /** Constructor.
       * 
       * Constructor of the PositionClient. This requires;
       * a pointer to Initialized and connected GIMI, minor
       * number of this interface (Used as GIMI minor number)
       *
       * @param[in] aGIMIPtr Pointer to GIMI used for communication
       * @param[in] aInterfaceMinor Interface minor number. Usually
       *            used to indicate the instance of devices of same
       *            type.
       * @param[in] aPositionBacklog_ms Defines how many milliseconds of
       *            positions are stored for future reference. Default
       *            is 3000ms.
       */     
      CPositionClient(gimi::GIMI *aGIMIPtr, const int aInterfaceMinor = -1,
                      const int aPositionBacklog_ms = 3000);

      
      /** Destructor.
       */
      ~CPositionClient();
      

      /** Open client interface.
       */
      MaCI::EMaCIError DoOpen(void);


      /** Close client interface.
       */
      MaCI::EMaCIError DoClose(void);


      /** Calls 'Initialize' on the Server side.
       * 
       * This function sends a command KCommandInitialize to position Server.
       * Its up to Server implementation to do something sane about it.
       *
       * @return                'true' when the command was successfully sent to
       *                        GIMnet. (True value does not guarantee a succesfull
       *                        delivery to server) 'false' value when some error
       *                        occured on the GIMnet layer.
       */
      bool SetInitialize(void);

      
      /** Sets position on the positioning device.
       *
       * This function sends the given position to the Position
       * service implementation, which then may decide what to do with
       * it. Probably it will be used for a best guess of current
       * whereabouts.
       *
       * @param[in] aPos        Position to set.
       * @return                'true' when the command was successfully sent to
       *                        GIMnet. (True value does not guarantee a succesfull
       *                        delivery to server) 'false' value when some error
       *                        occured on the GIMnet layer.
       */
      bool SetPosition(const MaCI::Position::TPose2D &aPos);
       
      /** Sets position, variance and probability on the positioning device.
       * \overload
       *
       * This function sends the given position, variance and
       * probability to the Position service implementation, 
       * which then may decide what to do with it.  Probably it 
       * will be used for a best guess of current whereabouts.
       * 
       * @param[in] aPos        Position to set
       * @param[in] aVar        Variance to set.
       * @param[in] aProb       Probability to set
       * @return                'true' when the command was successfully sent to
       *                        GIMnet. (True value does not guarantee a succesfull
       *                        delivery to server) 'false' value when some error
       *                        occured on the GIMnet layer.
       */
      bool SetPosition(const MaCI::Position::TPose2D &aPos,const MaCI::Position::TVariance2D &aVar, const MaCI::Position::TProbability &aProb);

      /**
       * Gets an PositionEvent sent by the server.
       *
       * @param[out] aData      PositionData is copied here on succesfull call.
       * @param aSequence       Pointer to sequence number. If this is NULL,
       *                        the most recent position is returned immediately.
       *                        If this is not NULL, the value pointed
       *                        should be set to -1 on the first call to this function.
       *                        After each call, the sequence number of the returned
       *                        data is stored here. If user wants to read all the
       *                        measures available, this value should not be
       *                        modified after the first call.
       * @param[in] aTimeout_ms Timeout value. If the operation is not completed
       *                        before timeout is reached, the operation fails.
       * @return                true - Operation was succesfull, new data is copied
       *                        to provided location.
       *                        false - Operation failed; timeout or generic error
       *                        encountered.
       */
      bool GetPositionEvent(MaCI::Position::CPositionData &INOUT, 
			    int *aSequence, 
                            const int aTimeout_ms);
	inline bool GetPositionEvent(MaCI::Position::CPositionData &aPose, const int aTimeout_ms){
			return GetPositionEvent(aPose, NULL, aTimeout_ms);
		}

      /**
       * Gets an PositionEvent from backlog by timestamp.
       *
       * @param[out] aData      PositionData is copied here on succesfull call.
       * @param[in] aTime       Use \p aTime as a selection basis. Returns position
       *                        _closest_ to the timestamp given.
       * @param[out] aTimeDiff  If this parameter is given (!NULL), it will
       *                        be set to time difference between the given time
       *                        and closest matching positions time.
       * @return                true - Operation was succesfull, new data is copied
       *                        to provided location.
       *                        false - Operation failed; timeout or generic error
       *                        encountered.
       */
      bool GetPositionEvent(MaCI::Position::CPositionData &INOUT, 
                            const gim::time &aTime,
                            gim::time *aTimeDiff = NULL);


      /** Assigns the Position client callback function. 
       *
       * This sets a function object for calling a position client
       * callback. If this is set, the interface calls the assigned
       * functions immediately when event is available.
       * 
       * \note As the function is run in the context of the receiving
       * thread, user must make sure that the callback function is
       * fast. As if the function executes too long, receiving events
       * is interrupted.
       *
       * @param[in] aPositionClientCallback Pointer to class implementing the interface
       *                                    CPositionClientCallback.
       */
      void SetPositionClientCallback(MaCI::Position::CPositionClientCallback *aPositionClientCallback) {
        iPositionClientCallback = aPositionClientCallback;
      }


      /** Clears the position backlog.
       */
      void ClearPositionBacklog() {
        iPositionBacklog.Clear();
      }

      // Derived from MaCI::CMaCI
      MaCI::EMaCIError Open();
      MaCI::EMaCIError Close();
      bool IsActive();
      //  void SetMaCICtrlServer(MaCI::MaCICtrl::CMaCICtrlServer *aMaCICtrlServer);
      void SetDefaultTarget(const std::string &aDefaultTarget);
      void SetStaticLinkDelay(const unsigned int aDelay_ms);
      bool SetGroupName(const std::string &aGroupName);	      
      bool SetDefaultTarget(const MaCI::MaCICtrl::SMaCISL &aMaCISL, const unsigned int aTimeout_ms = 2000);
      
/*      
    private:
      /// Thread runner function. Is in charge of receiving events.
      int ThreadFunction(const int aThreadNumber);
      int ProcessMessage(const gimi::GIMIMessage &msg);

      /// Last PositionData is stored here.
      CPositionData iPositionData;
      int iPositionDataSequence;
      CPositionClientCallback *iPositionClientCallback;

      // Backlog
      gim::CDataBacklog<CPositionData> iPositionBacklog;

      // Private copy const.
      CPositionClient(const CPositionClient &) 
        : CSync(),
          CThread(),
          CMaCI(NULL, 0,0,""),
          iPositionData(),
          iPositionDataSequence(),
          iPositionClientCallback(),
          iPositionBacklog(0,0) {}
      CPositionClient &operator=(const CPositionClient &) { return *this; }
*/
    };


    
  }
}

